package ac.uk.qmul.gemom.scenario;


import java.io.File;
import java.io.FileInputStream;
import java.lang.*;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Vector;

import javax.swing.JOptionPane;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.TreeNode;

import org.xml.sax.Attributes;
import org.xml.sax.InputSource;
import org.xml.sax.helpers.DefaultHandler;

import com.sun.org.apache.xerces.internal.parsers.*; 



/**
 * A parser for the scenario 
 * import the scenario configuration from xml file 
 * 
 * COPYRIGHT DISCLAIMER
 * Synopsis: All the source codes presented in this document are intellectual
 * properties of Queen Mary, University of London.
 * 
 * @year 2010
 * @author Peng Jiang, John Bigham, Jiayi Wu Jinfu Wang------------QMUL
 * @version 1.0 
 */
public class ScenarioFileParser {

	// the number of publisher
	public int client_num=0;
//	interval between time stamp
	public int time_step=0;
	public String system_start_time;
	
	public Subscription subscription;
	
	public Vector<String> nsList;
	/*
	*/
	public int max_rate=0;
	public int min_rate=0;
	
	public String counter_namespace;
	public String counter_topic;
	
	public ArrayList<PublisherSetting> publishers;
//	arraylist of hashmaps of each publisher config, according to start time in time segment?
//	TODO: a publisher config class implementing hashmap?
//	public HashMap publisher;
//	public String distri;
//	public String ingressIP;
//	public String topicNS;
//	public String timeStart;
//	public String timeStop;
	
	private TreeBuilder saxTree = null;

	//private static String file = "system1.xml";

	private String[] tag={"num","max","min", "time_step", "publisher", "task", "counter_namespace","counter_topic"};
	private String[] tag2={"t_id","time_start","time_stop","distribution",
			"message_length", "message_length_distribution", "mld_std_deviation",
			"ingressNode","mean_rate", "use_mean_rate", "min_rate", "max_rate",  
			"topicns", "publish_list", "fault_pattern", "delay_distribution", "mean_delay"};
	
	private String file;
	
	Vector<DefaultMutableTreeNode> list;
	Vector<DefaultMutableTreeNode> list2;
	

	public ScenarioFileParser(File xmlfile)
	{
		publishers = new ArrayList<PublisherSetting>();
		DefaultMutableTreeNode top = new DefaultMutableTreeNode("root");
		saxTree = new TreeBuilder(top);
		
		if(xmlfile.exists())
		{
			file=xmlfile.getAbsolutePath();
		}
		else{
			return; 
		}

		try{
			SAXParser saxParser = new SAXParser();
			saxParser.setContentHandler(saxTree);
			saxParser.parse(new InputSource(new FileInputStream(file)));
			
			list= new Vector<DefaultMutableTreeNode>();
			list2= new Vector<DefaultMutableTreeNode>();
			
			nsList = new Vector<String>();

			analyze();
			
		}catch(Exception ex){
			ex.printStackTrace();
		}
		
	}
	
	public TreeBuilder getSaxTree(){
		if(saxTree != null){
		    return saxTree;
		}
		else
			return null;
	}

	private void analyze()
	{
		DefaultMutableTreeNode root=saxTree.getTree();
		
		list.removeAllElements();	
		findNode(tag[0],root, list);
		client_num=Integer.parseInt(list.get(0).getFirstLeaf().toString());
		
		list.removeAllElements();
		findNode(tag[1],root, list);
		max_rate=Integer.parseInt(list.get(0).getFirstLeaf().toString());

		list.removeAllElements();		
		findNode(tag[2],root, list);

		min_rate=Integer.parseInt(list.get(0).getFirstLeaf().toString());
		
		list.removeAllElements();		
		findNode(tag[3],root, list);

		time_step=Integer.parseInt(list.get(0).getFirstLeaf().toString());
		
		list.removeAllElements();	
		findNode(tag[6],root, list);
		counter_namespace = list.get(0).getFirstLeaf().toString();
		
		list.removeAllElements();	
		findNode(tag[7],root, list);
		counter_topic = list.get(0).getFirstLeaf().toString();

		list.removeAllElements();	
		findNode("system_start_time",root, list);
		system_start_time=list.get(0).getFirstLeaf().toString();
		
		list.removeAllElements();		
		findNode(tag[4],root, list);
//		build PubConfigs
		for (DefaultMutableTreeNode publisherNode : list){
			
			PublisherSetting publisherSetting = new PublisherSetting();
			// task nodes' vector
			Vector<DefaultMutableTreeNode> taskList=new Vector<DefaultMutableTreeNode>();
			// time seg nodes' vector
			Vector<DefaultMutableTreeNode> segList=new Vector<DefaultMutableTreeNode>();
			publisherSetting.id=Integer.parseInt((publisherNode.getFirstChild().toString().split("\\s=\\s"))[1]);
			
			// empty other tree branches' results before loading the current branch
			taskList.removeAllElements();
			
			
			// find all task nodes belonging to the current publisher branch
			ScenarioFileParser.findNode(tag[5],publisherNode,taskList);
			
			for (DefaultMutableTreeNode taskNode :taskList){
				int taskId, segId;
				taskId = Integer.parseInt((taskNode.getFirstChild().toString().split("\\s=\\s"))[1]);
				
				publisherSetting.addTask(taskId-1);
				
				// empty other tree branches' results before loading the current branch	
				segList.removeAllElements();	
				ScenarioFileParser.findNode("time_segment",taskNode,segList);
				for (DefaultMutableTreeNode a :segList){
//					each time_segment node
					if (a.getChildCount() > 0) {
						TimeSeg t = new TimeSeg();

						t.t_id=Integer.parseInt((a.getFirstChild().toString().split("\\s=\\s"))[1]);
						
//						tag2={"t_id","time_start","time_stop","distribution","ingressNode","mean_rate","topicns"};
						list2.removeAllElements();		
						findNode(tag2[1],a, list2);
						t.time_start=convertTimeString(list2.get(0).getFirstLeaf().toString());
						
						list2.removeAllElements();		
						findNode(tag2[2],a, list2);
						t.time_stop=convertTimeString(list2.get(0).getFirstLeaf().toString());
						
						list2.removeAllElements();		
						findNode(tag2[3],a, list2);
						t.distribution=list2.get(0).getFirstLeaf().toString();
						
						list2.removeAllElements();		
						findNode(tag2[4],a, list2);
						t.message_length=Integer.parseInt(list2.get(0).getFirstLeaf().toString());
						
						list2.removeAllElements();		
						findNode(tag2[5],a, list2);
						t.message_length_distribution=list2.get(0).getFirstLeaf().toString();
						
						list2.removeAllElements();		
						findNode(tag2[6],a, list2);
						t.mld_std_deviation=Double.parseDouble(list2.get(0).getFirstLeaf().toString());
						
						list2.removeAllElements();		
						findNode(tag2[7],a, list2);
						t.ingressNode=list2.get(0).getFirstLeaf().toString();
						
						list2.removeAllElements();		
						findNode(tag2[8],a, list2);
						t.mean_rate=Double.parseDouble(list2.get(0).getFirstLeaf().toString());
						
						list2.removeAllElements();		
						findNode(tag2[9],a, list2);
						String use = list2.get(0).getFirstLeaf().toString();
						if(use.equalsIgnoreCase("yes"))
						    t.use_mean_rate=true;
						else
							t.use_mean_rate=false;
						
						list2.removeAllElements();		
						findNode(tag2[10],a, list2);
						t.min_rate=Double.parseDouble(list2.get(0).getFirstLeaf().toString());
						
						list2.removeAllElements();		
						findNode(tag2[11],a, list2);
						t.max_rate=Double.parseDouble(list2.get(0).getFirstLeaf().toString());
						
						list2.removeAllElements();		
						findNode(tag2[12],a, list2);
						t.topicns=list2.get(0).getFirstLeaf().toString();
						
						this.nsList.add(getNsName(t.topicns));
//						for(int i=1; i<=tag2.length; i++){
//							list2.removeAllElements();		
//							findNode(tag2[i],root, list2);
//						}
						//					HashMap<String, String> tsMap = new HashMap();

						//					for (Enumeration<DefaultMutableTreeNode> e=a.children(); e.hasMoreElements(); ){
						//						DefaultMutableTreeNode b= e.nextElement();
						//						if(b.toString().equals("t_id=")){
						//							t.t_id=
						//						}
						////						tsMap.put(b.toString(),b.getFirstLeaf().toString());
						
						list2.removeAllElements();		
						findNode(tag2[13],a, list2);
						String tempPubList = list2.get(0).getFirstLeaf().toString();
						String [] names = tempPubList.split("/");
						for(int i = 0; i < names.length; i++){
						    t.publish_list.add(names[i]);
						}
						
						list2.removeAllElements();		
						findNode(tag2[14],a, list2);
						t.fault_pattern = list2.get(0).getFirstLeaf().toString();
						
						list2.removeAllElements();		
						findNode(tag2[15],a, list2);
						t.delay_distribution=list2.get(0).getFirstLeaf().toString();
						
						list2.removeAllElements();		
						findNode(tag2[16],a, list2);
						t.mean_delay=Double.parseDouble(list2.get(0).getFirstLeaf().toString());
						
						publisherSetting.addSegByTask(taskId-1, t);	
					}
			    }// end of segment loop
					
			}// end of tasks loop
			publishers.add(publisherSetting);
		}// end of publisher loop
	}
	
	/**
	 * 
	 * @param String, the tag  you want to find
	 * @param DefaultMutableTreeNode, the node you want to find
	 * */

	public static void findNode(String s, DefaultMutableTreeNode node, Vector<DefaultMutableTreeNode> list)
	{
		if (node.getChildCount() >= 0) {
			for (Enumeration e=node.children(); e.hasMoreElements(); ) {
				DefaultMutableTreeNode n = (DefaultMutableTreeNode)e.nextElement();
				if(n.toString().equals(s))
					list.add(n);
				else
					findNode(s,n, list);
			}
		}
	}
	
	private static String getNsName(String topicNs)
	{
		String ns;
		String tp;
		if(topicNs.contains("@/")){
		    String[] tpns=topicNs.split("@/");
		    tp=tpns[0];
		    ns=tpns[1];
		}
		else{
		    tp = topicNs;
		    ns = topicNs;
		}

        return ns;
		
	}
	
	public PublisherSetting getPublisherSetting(int index)
	{ 

        return publishers.get(index);
		
	}
	
	// return time in seconds
	public static double convertTimeString(String s)
	{
		// time string is in the form XX:XX:XX and the expression stands for hour:minute:second
		String[] tmp=s.split(":");
	
		double[] time = {Double.parseDouble(tmp[0]), Double.parseDouble(tmp[1]), Double.parseDouble(tmp[2]) };
		
		return time[0]*60*60 + time[1]*60 + time[2];
	}
	
//	public static void main(String[] args){
//		fileParser fp= new fileParser();
//		System.out.println("");
//	}


}

